package com.reach.redis.factory;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.ReflectionUtils;

import com.reach.redis.annotation.CacheEvict;
import com.reach.redis.annotation.Cacheable;
import com.reach.redis.bo.CacheConfig;
import com.reach.redis.manager.ManagerCache;
import com.reach.redis.utils.GsonUtils;

//ApplicationContextAware, BeanFactoryPostProcessor,
//		InitializingBean, FactoryBean<ManagerCache>,

public abstract class AbstractCacheFactory implements  BeanPostProcessor {

	private static final Logger logger = LoggerFactory.getLogger(AbstractCacheFactory.class);
	

	private ManagerCache  managerCache 	 = new ManagerCache();

	
	private List<String> filterClass = Arrays.asList(new String[] {"java","org.springframework","org.mybatis","org.apache"});


	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {

		return bean;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		if(isExistClassName(bean)) {//!ManagerCache.enableCache ||
			return bean;
		}

		Method[] methods = ReflectionUtils.getAllDeclaredMethods(bean.getClass());
		if (methods != null) {
			for (Method method : methods) {
				Annotation  cacheable = AnnotationUtils.findAnnotation(method,Cacheable.class);
				Annotation  cacheEvict = AnnotationUtils.findAnnotation(method,CacheEvict.class);
				if(cacheable != null) {
					CacheConfig cacheConfig = handle(method, bean, cacheable,beanName);
					managerCache.initProxy(cacheConfig);
					if(logger.isDebugEnabled()) {
						logger.debug("Cache cacheable is [{}].",GsonUtils.toString(cacheable));
					}
				}	
				
				if(cacheEvict != null) {
					CacheConfig cacheConfig = handle(method, bean, cacheEvict,beanName);
					managerCache.initProxy(cacheConfig);
					if(logger.isDebugEnabled()) {
						logger.debug("Cache cacheEvict is [{}].",GsonUtils.toString(cacheEvict));
					}
				}	
				
			}

			
		}
		return bean;
	}
	
	private CacheConfig handle(Method method,Object bean,Annotation annotation, String beanName) {
		CacheConfig cacheConfig = new CacheConfig();
		cacheConfig.setTargetMethod(method);
		cacheConfig.setTargetObject(bean);
		cacheConfig.setCache(annotation);
		cacheConfig.setBeanName(beanName);
		return cacheConfig;
		
	}
	
	private boolean isExistClassName(Object method) {
		if(method != null) {
			for(String filter : filterClass) {
				if(method.getClass().getName().indexOf(filter) > -1) {
					return true;
				}
			}
		}
		return false;
		
	}


}